package com.example.ui.chart.pie;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;

import androidx.annotation.Nullable;

import java.util.ArrayList;

public class PieChartView extends View implements ValueAnimator.AnimatorUpdateListener {

    private static final String TAG = "PieChartView";

    //1、展示的颜色  默认   用户可以设置
    private int[] mColors = {0xFFCCFF00, 0xFF6495ED, 0xFFE32636, 0xFF800000, 0xFF808000, 0xFFFF8C69, 0xFF808080,
            0xFFE6B800, 0xFF7CFC00};
    //起始角度   用户可以设置
    private float mStartAngle = 0;
    //数据源
    private ArrayList<PieData> mData;
    //宽高
    private int mRealWidth, mRealHeight;
    //画笔
    private Paint mPaint = new Paint();
    //加载动画时长
    private long mDuration = 500;
    //加载动画
    private ValueAnimator valueAnimator;
    //绘制终止角度
    private int endAngle = 360;
    private float r;
    private float touchAngle;
    private RectF rect;
    private RectF rectSelect;
    private int lastSelectIndex = -1;
    private float centerX;
    private float centerY;
    private int selectIndex = -1;
    private SelectIndexChangeListener listener;
    VelocityTracker mVelocityTracker = null;

    public PieChartView(Context context) {
        super(context);
        init(context);
    }

    public PieChartView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public void init(Context context) {
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setAntiAlias(true);

        valueAnimator = new ValueAnimator();
        valueAnimator.setIntValues(0, 360);
        valueAnimator.setDuration(mDuration);
        valueAnimator.addUpdateListener(this);

        int scaledTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
        Log.d(TAG, "initData: scaledTouchSlop = " + scaledTouchSlop);
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        Log.d(TAG, "onMeasure: ------------ widthMode ---------------");
        switch (widthMode) {
            case MeasureSpec.AT_MOST: {
                Log.d(TAG, "onMeasure: AT_MOST");
            }
            break;
            case MeasureSpec.EXACTLY: {
                Log.d(TAG, "onMeasure: EXACTLY");
            }
            break;
            case MeasureSpec.UNSPECIFIED: {
                Log.d(TAG, "onMeasure: UNSPECIFIED");
            }
            break;
        }
        Log.d(TAG, "onMeasure: ------------ heightMode ---------------");
        switch (heightMode) {
            case MeasureSpec.AT_MOST: {
                Log.d(TAG, "onMeasure: AT_MOST");
            }
            break;
            case MeasureSpec.EXACTLY: {
                Log.d(TAG, "onMeasure: EXACTLY");
            }
            break;
            case MeasureSpec.UNSPECIFIED: {
                Log.d(TAG, "onMeasure: UNSPECIFIED");
            }
            break;
        }

        Log.d(TAG, "onMeasure:  widthSize = " + widthSize + " heightSize = " + heightSize);
//        setMeasuredDimension();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        Log.d(TAG, "onSizeChanged: w = " + w + " h = " + h + " oldw = " + oldw + " oldh = " + oldh);
        Log.d(TAG, "onSizeChanged: getPaddingTop = " + getPaddingTop()
                + " getPaddingBottom = " + getPaddingBottom()
                + " getPaddingLeft = " + getPaddingLeft()
                + " getPaddingRight = " + getPaddingRight());
        mRealHeight = h;
        mRealWidth = w;
        r = Math.min((mRealWidth - getPaddingLeft() - getPaddingRight()) / 2.0f,
                (mRealHeight - getPaddingTop() - getPaddingBottom()) / 2.0f);
        //绘制区域
        rect = new RectF(-r + 150, -r + 150, r - 150, r - 150);
        rectSelect = new RectF(-r + 50, -r + 50, r - 50, r - 50);
        centerX = mRealWidth / 2;
        centerY = mRealHeight / 2;

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if ((mData == null) || (mData.size() == 0)) {
            return;
        }

        float currentStartAngle = mStartAngle;    //起始坐标
        canvas.translate(mRealWidth / 2, mRealHeight / 2);    //将画布坐标原点移动到中心位置

        for (int i = 0; i < mData.size(); i++) {
            PieData pie = mData.get(i);
            mPaint.setColor(pie.getColor());
            //期望的角度比已绘制的角度大
            if (endAngle > currentStartAngle) {
                //才绘制
                if (i == selectIndex) {
                    canvas.drawArc(rectSelect, currentStartAngle, pie.getAngle(), true, mPaint);
                } else {
                    canvas.drawArc(rect, currentStartAngle, Math.min(pie.getAngle(), endAngle - currentStartAngle), true, mPaint);
                }
            } else {
                break;
            }
            currentStartAngle += pie.getAngle();
        }
    }

    public void setmColors(int[] mColors) {
        this.mColors = mColors;
    }

    public void setmStartAngle(float mStartAngle) {
        this.mStartAngle = mStartAngle;
    }

    public SelectIndexChangeListener getListener() {
        return listener;
    }

    public void setListener(SelectIndexChangeListener listener) {
        this.listener = listener;
    }

    public void setmData(ArrayList<PieData> mData) {
        this.mData = mData;
        initData(this.mData);
    }

    private void initData(ArrayList<PieData> mData) {
        if ((mData == null) || (mData.size() == 0)) {
            //数据有问题
            return;
        }

        float sunValue = 0;
        for (int i = 0; i < mData.size(); i++) {
            PieData pie = mData.get(i);
            sunValue += pie.getValue();
            pie.setColor(mColors[i % mColors.length]);
        }

        //得到百分比和角度
        for (int i = 0; i < mData.size(); i++) {
            PieData pie = mData.get(i);
            float percentage = pie.getValue() / sunValue;
            pie.setAngle(percentage * 360.0f);
            pie.setPercentage(percentage);
        }
        touchAngle = -1;
        valueAnimator.start();



    }

    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        int value = (int) animation.getAnimatedValue();
        endAngle = value;
        Log.d(TAG, "onAnimationUpdate: endAngle = " + endAngle);
        invalidate();
    }

    private boolean isIn = false;

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }

        mVelocityTracker.addMovement(event);
        float x = event.getX();
        float y = event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE: {
                touchAngle = getRotationBetweenLines(mRealWidth / 2, mRealHeight / 2, x, y);
                checkIsIn(x,y);
                float currentStartAngle = mStartAngle;
                selectIndex = -1;

                for (int i = 0; i < mData.size(); i++) {
                    PieData pie = mData.get(i);
                    if (touchAngle != -1 && touchAngle >= currentStartAngle && touchAngle < currentStartAngle + pie.getAngle()) {
                        selectIndex = i;
                    }
                    currentStartAngle += pie.getAngle();
                }

                if (isIn && selectIndex != -1 && lastSelectIndex != selectIndex) {
                    Log.d(TAG, "onTouchEvent: invalidate isIn = " + isIn + " selectIndex = " + selectIndex);
                    if (listener != null) {
                        listener.selectIndexChange(mData.get(selectIndex));
                    }
                    lastSelectIndex = selectIndex;
                    invalidate();
                }
            }
            break;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP: {
                checkIsIn(x,y);
                //求伪瞬时速度
                mVelocityTracker.computeCurrentVelocity(1000);
                float velocityX = mVelocityTracker.getXVelocity();
                float velocityY = mVelocityTracker.getYVelocity();
                Log.d(TAG, "onTouchEvent: velocityX = " + velocityX + "  velocityY = " + velocityY);
                mVelocityTracker.clear();
                mVelocityTracker.recycle();
                mVelocityTracker = null;
                if (!isIn && selectIndex != -1) {
                    lastSelectIndex = -1;
                    selectIndex = -1;
                    invalidate();
                }
            } break;
        }
        return true;
    }

    //检查坐标是否在显示区域内
    private void checkIsIn(float x, float y) {
        if (Math.sqrt((x - centerX) * (x - centerX) + (y - centerY) * (y - centerY)) < r - 150) {
            isIn = true;
        } else {
            isIn = false;
        }
        Log.d(TAG, "checkIsIn: isIn = " + isIn);
    }

    //获取从起点线到终点线经过的角度
    public float getRotationBetweenLines(float centerX, float centerY, float xInView, float yInView) {
        float x = xInView - centerX;
        float y = yInView - centerY;
        double z = Math.sqrt(x * x + y * y);
        float round = (float) (Math.asin(Math.abs(y) / z) / Math.PI * 180);
        //四个象限做处理
        if (x < 0 && y > 0) {
            return 180 - round;
        } else if (x < 0 && y < 0) {
            return 180 + round;
        } else if (x > 0 && y < 0) {
            return 360 - round;
        } else {
            return round;
        }
    }

    public interface SelectIndexChangeListener {
        void selectIndexChange(PieData data);
    }
}
